cmake_minimum_required(VERSION 3.21.0)
project(chisel-x VERSION 0.1)

include(CTest)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
if (NOT DEFINED IS_SUBDIR)
    include(CPack)
    set(IS_SUBDIR ON)
endif ()
enable_testing()

# enable_language(ASM CXX C)

set(X_ROOT ${PROJECT_SOURCE_DIR})
set(CHISEL_X 1)

message(STATUS "${PROJECT_NAME} started building on ${CMAKE_SYSTEM_NAME} using ${CMAKE_GENERATOR}!")

set(ROOT ${PROJECT_SOURCE_DIR})
set(MODULE_ROOT ${ROOT}/src/main/scala/modules)
set(LITE_ROOT ${PROJECT_SOURCE_DIR}/nemu-lite)

message(STATUS "Install to ${CMAKE_INSTALL_PREFIX}")

option(BATCH_MODE "Building and testing with console only" OFF)
if ($ENV{BATCH_MODE})
    set(BATCH_MODE ON)
endif ()
option(USE_SYSTEMC "Download SystemC Library" OFF)
option(DISABLE_FORMAT_WARNING "Disable format warning [-Wno-format -Wno-format-security]" ON)
option(CI_MODE "Online CI Mode" OFF)
option(USE_MILL "Use mill to build instead of sbt" OFF)
if (CI_MODE)
    set(BATCH_MODE ON)
endif ()
option(IGNORE_SCALA_UPDATE "Ignore scala update and just make from verilog. If no verilog found, will call `main' to generate verilog." OFF)

if (DISABLE_FORMAT_WARNING)
    add_compile_options(-Wno-format)
    add_compile_options(-Wno-format-security)
endif ()

# enable CMake extra modules
include(FetchContent)
include(ExternalProject)

if (BATCH_MODE)
    set(CONFIG_FILE_NAME .console.config)
else ()
    set(CONFIG_FILE_NAME .config)
endif ()
set(CONFIG_FILE_PATH ${ROOT}/${CONFIG_FILE_NAME})

# copy HHVM source files by link
# if (NOT EXISTS "${CMAKE_SOURCE_DIR}/src/main/scala/modules/HHVM")
#     if (WIN32)
#         message(STATUS "HHVM: mklink /j \"${CMAKE_SOURCE_DIR}/src/main/scala/modules/HHVM\" \"${CMAKE_SOURCE_DIR}/HHVM/HHVM/src/modules/HHVM\"")
#         file(WRITE "${CMAKE_BINARY_DIR}/link-HHVM.bat" "@mklink /j \"${CMAKE_SOURCE_DIR}/src/main/scala/modules/HHVM\" \"${CMAKE_SOURCE_DIR}/HHVM/HHVM/src/modules/HHVM\"")
#         execute_process(COMMAND "${CMAKE_BINARY_DIR}/link-HHVM.bat"
#                 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
#                 RESULT_VARIABLE HHVM_LINK_RESULT)
#         if (NOT HHVM_LINK_RESULT EQUAL 0)
#             message(FATAL_ERROR "Failed when linking HHVM files! mklink returns ${HHVM_LINK_RESULT}")
#         endif ()
#     else ()
#         execute_process(COMMAND ln -s "${CMAKE_SOURCE_DIR}/HHVM/HHVM/src/modules/HHVM" "${CMAKE_SOURCE_DIR}/src/main/scala/modules/HHVM"
#                 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
#                 RESULT_VARIABLE HHVM_LINK_RESULT)
#     endif ()
# endif ()

set(ARGS_LIST)
include(${LITE_ROOT}/cmake/config.cmake)
generate_config()
if (CI_MODE)
    file(COPY_FILE ${CONFIG_FILE_PATH} ${CMAKE_BINARY_DIR}/.config)
endif ()
read_config(${CONFIG_FILE_PATH} ARGS_LIST)

if (CI_MODE)
    set(CONFIG_ITRACE)
    # list(REMOVE_ITEM ARGS_LIST "CONFIG_ITRACE")
endif ()

if (WIN32)
    include(${X_ROOT}/cmake/verilator-mingw.cmake)
else ()
    find_package(verilator)
    if (NOT verilator_FOUND)
        message(FATAL_ERROR "No Verilator library found on ${CMAKE_PLATFORM}!")
    endif ()
endif ()

include(${X_ROOT}/cmake/espresso.cmake)

# Resources
#file(GLOB_RECURSE RESOURCES "${RESOURCE_DIR}/*")
#message(STATUS "Copying Resources file(s): ${RESOURCES}")
#file(COPY ${RESOURCES} DESTINATION ${CMAKE_BINARY_DIR}/)

# Linking
if (NOT ${CMAKE_GENERATOR} STREQUAL "Visual Studio 16 2019")
    link_libraries(-lpthread)
endif ()

message("Binary Dir for ${PROJECT_NAME}: ${PROJECT_BINARY_DIR}")
add_subdirectory(${X_ROOT}/nemu-lite)

#include(${LITE_ROOT}/cmake/sdl2.cmake)
#include(${LITE_ROOT}/cmake/readline.cmake)
#message("SOURCE_FILES_LITE = ${SOURCE_FILES_LITE}")
#message("INCLUDE_DIRS_LITE = ${INCLUDE_DIRS_LITE}")

# Include
set(INCLUDE_DIRS
        "${X_ROOT}/src"
        "${X_ROOT}/src/include"
        "${CMAKE_BINARY_DIR}/include"
        ${INCLUDE_DIRS_LITE}
        )
message(STATUS "Include dirs: ${INCLUDE_DIRS}")
include_directories(${INCLUDE_DIRS})

file(GLOB_RECURSE X_SOURCE_FILES
        "${X_ROOT}/src/model/*.c" "${X_ROOT}/src/model/*.cpp")
file(GLOB TEST_FILES "${X_ROOT}/tests/*.c" "${X_ROOT}/tests/*.cpp")
file(GLOB LIBRARY_FILES
        "${PROJECT_SOURCE_DIR}/tests/shared/*.c"
        "${PROJECT_SOURCE_DIR}/tests/shared/*.cpp")
list(APPEND TEST_FILES ${LIBRARY_FILES})
set(INSTALL_TARGETS)
if (NOT DEFINED CONFIG_X_DIFFTEST)
    set(CONFIG_X_DIFFTEST OFF)
endif ()

# Resources
set(RESOURCE_DIR ${PROJECT_SOURCE_DIR}/resources)
file(GLOB_RECURSE RESOURCES "${RESOURCE_DIR}/*")
message(STATUS "Copying Resources file(s): ${RESOURCES}")
file(COPY ${RESOURCES} DESTINATION ${PROJECT_BINARY_DIR}/)

include(${LITE_ROOT}/cmake/difftest.cmake)

include(${X_ROOT}/cmake/x-utils.cmake)
# Add run modules main
set(RUN_MODULES_FILE ${X_ROOT}/src/programs/run_modules.cpp)
list(REMOVE_ITEM X_SOURCE_FILES ${RUN_MODULES_FILE})
add_executable(run-modules ${RUN_MODULES_FILE} ${X_SOURCE_FILES})
add_test(NAME run-modules COMMAND run-modules)
install(TARGETS run-modules DESTINATION bin)

file(GLOB CHISEL_MODULE_PATHS "${MODULE_ROOT}/*")
set(CHISEL_MODULES)
foreach (CHISEL_MODULE_PATH ${CHISEL_MODULE_PATHS})
    string(REGEX REPLACE ".+/(.+)" "\\1" CHISEL_MODULE_NAME ${CHISEL_MODULE_PATH})
    if (NOT "${CHISEL_MODULE_NAME}" STREQUAL ".gitignore")
        list(APPEND CHISEL_MODULES ${CHISEL_MODULE_NAME})
    endif ()
endforeach ()
#string(REGEX REPLACE ".+/(.+)" "\\1" CHISEL_MODULES ${CHISEL_MODULE_PATH})
message(STATUS "ChiselX Modules: ${CHISEL_MODULES}")
foreach (MODULE_NAME ${CHISEL_MODULES})
    string(TOUPPER ${MODULE_NAME} MODULE_UPPER)
    if (NOT DEFINED CONFIG_XM_${MODULE_UPPER})
        message("Blocked module: ${MODULE_NAME}")
        list(REMOVE_ITEM CHISEL_MODULES ${MODULE_NAME})
    endif ()
endforeach ()
my_add_module("${CHISEL_MODULES}")
add_extra_definitions()

my_add_tests(INSTALL_TARGETS ${CONFIG_X_DIFFTEST})
message(STATUS "Targets to Install: ${INSTALL_TARGETS}")
install(TARGETS ${INSTALL_TARGETS} DESTINATION bin)

if (NOT "${CONFIG_X_TESTS_IMAGES}" STREQUAL "")
    file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/images")
    file(GLOB INSTALL_BINARY_FILES "${CMAKE_BINARY_DIR}/images/*.bin")
else ()
    file(GLOB INSTALL_BINARY_FILES "${CMAKE_BINARY_DIR}/*.bin")
    # message(STATUS "INSTALL_BINARY_FILES = ${INSTALL_BINARY_FILES}; CONFIG_X_TESTS_IMAGES = ${CONFIG_X_TESTS_IMAGES}")
endif ()
install(FILES ${INSTALL_BINARY_FILES} DESTINATION bin)

# 波形文件夹
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/waveforms)

if (USE_SYSTEMC)
    add_dependencies(verilator-test systemc)
endif ()
